/* appjet:version 0.1 */
/* appjet:server */
import("storage");
import("lib-jquery");
import("lib-jmaps");
import("lib-google-gears");
import("lib-json");
import("lib-xmlobj");
import("lib-text-trim");
import("lib-iplocation");
import("lib-rpx");
import("dlog");

if (!storage.google_api_key) {
    print(html("<h1>Warning</h1>: You have not set your IP key.  To do this, do the following in your app shell"));
    print(html("""<pre>import("storage");<br />storage.google_api_key = "MY_KEY"</pre>"""));
}
if (!storage.user_data) storage.user_data = {};

if (rpx_user && !storage.user_data[rpx_user.identifier]) {
    storage.user_data[rpx_user.identifier] = {};
    storage.user_data[rpx_user.identifier].displayName = rpx_user.displayName;
    storage.user_data[rpx_user.identifier].email = rpx_user.email;
    storage.user_data[rpx_user.identifier].lastLogin = rpx_user.loginDate;
    if (rpx_user.address && rpx_user.address.postalCode)
        storage.user_data[rpx_user.identifier].postcode = rpx_user.address.postalCode;
    storage.user_data[rpx_user.identifier].locations = new StorableCollection();
} else if (rpx_user && storage.user_data[rpx_user.identifier]) {
     storage.user_data[rpx_user.identifier].lastLogin= rpx_user.loginDate;
}

function get_main(){
    var logged_in = (rpx_user ? "true" : "false");

    page.setTitle('Live Locations');
    page.head.write(SCRIPT({src: "http://maps.google.com/maps?file=api&amp;v=2&amp;key=" + storage.google_api_key}));
    page.head.write(SCRIPT({src: "http://jmaps.googlecode.com/svn/tags/deprecated/jmapsdemos/media/js/lib/jquery.jgrowl_minimized.js"}));
    page.head.write('<script type="text/javascript">var clientIp = "'+request.clientAddr+'";</script>');
    page.head.write('<script type="text/javascript">logged_in = '+ logged_in +';</script>');
    print(image('http://1.latest.jmapsdemos.appspot.com/images/jmaps-title.png'));
    print(RPX("live-locations"));
    
    if (rpx_user) {
        print(html("""
            <br style="clear:both;" />
            <div id="map-container">
                <div id="map">Map loading...Attempting to find your location</div>
                <div id="directions"></div>
            </div>"""));
        print(html("""
            <div id="map-sidebar"></div>
        """));
    }
}
            
function get_lookup() {
    page.setMode('plain');
    if (request.params){
        var results = getIpLocation(request.params.ip);
    } else {
        var results = {'success':'false'};
    }
    print(JSON.stringify(results));
}

function get_last_locations() {
    var locations = storage.user_data[rpx_user.identifier].locations;
    var return_locations = [];
    page.setMode('plain');
    if (request.params) {
        var limit = parseInt(request.params.limit, 10);
        var count = 0;
        locations.sortBy("-timestamp").limit(limit).forEach(function(location){
           return_locations.push({
               'latitude':location.lat,
               'longitude':location.lng,
               'address': location.address,
               'timestamp': location.timestamp
            });
        });
        var results = {'success':true, 'locations': return_locations};
    } else {
        var results = {'success':false};
    }
    print(JSON.stringify(results));
}

function post_position_success() {
    var locations = storage.user_data[rpx_user.identifier].locations;
    page.setMode('plain');
    if (request.params) {
        var lat = request.params.lat;
        var lng = request.params.lng;
        var address= request.params.address;
        var now = parseInt(new Date().getTime().toString().substring(0, 10));
        locations.add({'timestamp':now, 'lat': lat, 'lng': lng, 'address': address});
        var results = {'success':true};
    } else {
        var results = {'success':false};
    }
    print(JSON.stringify(results));
}

dispatch();

/* appjet:client */
jQuery(document).ready(function(){
    if (logged_in) {
        jQuery.jGrowl('Welcome to jMaps.  I will now try determine your location.', {'header': 'jMaps Mapping Demo', 'life': 5000});
        var geoCoder = determineGeoLocation();
        if (geoCoder) {
            jQuery.jGrowl('Using W3C Compliant Encoder.', {'header': 'jMaps Mapping Demo', 'life': 5000});
            geoCoder.getCurrentPosition(positionSuccess, positionError, {'enableHighAccuracy':true, 'timeout':30, 'maximumAge':600});
        } else {
            jQuery.jGrowl('No Geocoding in browser, Falling back to IP based location.', {'header': 'jMaps Mapping Demo', 'life': 5000});
            getIpBasedLocation()
        }
    }
});

function determineGeoLocation() {
    var encoder = false;
    var test = typeof navigator.geolocation;
    if ( test !== 'undefined' ) {
        encoder = navigator.geolocation;
    } else {
        try {
            encoder = google.gears.factory.create('beta.geolocation');
        } catch (error) {
            //Fall back to IP Based
            encoder = false;
        }
    }
    return encoder;
};

function getIpBasedLocation() {
    var request_vars = {'ip':clientIp};
    var url = '/lookup';
    jQuery.ajax({
        'type':'GET',
        'url': url,
        'data':request_vars,
        'dataType':'json',
        'success': function(data) {
            jQuery.each(data, function(i, service) {
                if (service.success) {
                    jQuery.jGrowl('Found your location using ' + service.service + ', creating map.', {'header': 'jMaps Mapping Demo', 'life': 5000});
                    positionSuccess(service);
                    return false;
                } else {
                    if (i === (data.length - 1)) {
                        jQuery.jGrowl('Cannot determine your location, falling back to the Googleplex.', {'header': 'jMaps Mapping Demo', 'life': 5000});
                        positionSuccess({'latitude': 37.4419, 'longitude': -122.1419});
                        return false;
                    }
                }
            });
        },
        'error': function (error) {
            jQuery.jGrowl(error.message, {'header': 'jMaps Mapping Demo', 'life': 5000});
        }
    });
};

function outputLastTenLocations() {
    jQuery.get('/last_locations', {'limit':10}, function(data, success) {
        if (data.success) {
            var output = ['<ol>'];
            jQuery.each(data.locations, function(i, location) {
                output.push('<li>' + location.address + '<br />(' + location.latitude + ', ' + location.longitude + ')</li>');
            });
            output.push('</ol>');
            jQuery('#map-sidebar').html(output.join(''));
        }
    }, 'json');
}

function getLocationAddress(position) {
    jQuery.jGrowl('Attempting to find address', {'header': 'jMaps Mapping Demo', 'life': 5000});
    jQuery('#map').jmap('SearchAddress', {
        'query': new GLatLng(position.latitude, position.longitude),
        'returnType':'getLocations'
    }, function(result, options) {
        console.log(result);

    var total_addresses = result.Placemark.length;
    if (total_addresses > 1) {
        jQuery.jGrowl('More than one address returned for your location.  Please select the closest address next to the map.', {'header': 'jMaps Mapping Demo', 'life': 5000});
        var output = ['<div id="address-find-container">'];
        output.push('<div class="instructions">');
            output.push('<p>Below are a list of addresses returned from google for your location.  Please select the closest address from below, or type in your address if none are correct.</p>');
        output.push('</div>');
        
        output.push('<ol class="address-list">');
        jQuery.each(result.Placemark, function(i, location) {
            
            jQuery('#map').jmap('AddMarker', {
               'pointLatLng':  [location.Point.coordinates[1], location.Point.coordinates[0]]
            }, function(marker, options) {
                GEvent.addListener(marker, "click", function(){
                    var save_results = {
                        'lat': location.Point.coordinates[1],
                        'lng': location.Point.coordinates[0],
                        'address': location.address
                    }
            
                    jQuery.post('/position_success', save_results, function(data, success) {
                        jQuery.jGrowl('Your position has been saved.', {'header': 'jMaps Mapping Demo', 'life': 5000});
                        jQuery('#map-sidebar').find('#address-find-container').fadeOut('slow', function(){
                            jQuery(this).remove();
                            var thisMap = Mapifies.MapObjects.Get(jQuery('#map').get(0));
                            thisMap.clearOverlays()
                            outputLastTenLocations();
                        });
                    }, 'json');
                });
            });
            
            output.push('<li>');
                output.push('<a class="location" rel="'+i+'" href="#">' + location.address + '</a>');
            output.push('</li>');
        });
        output.push('</ol>');
        output.push('</div>');
        jQuery('#map-sidebar').html(output.join(''));
        jQuery('#map-sidebar').find('.location').click(function(){
            jQuery.jGrowl('Saving your location now.', {'header': 'jMaps Mapping Demo', 'life': 5000});
            var index = jQuery(this).attr('rel');
            var location = result.Placemark[index];
            var save_results = {
                'lat': location.Point.coordinates[1],
                'lng': location.Point.coordinates[0],
                'address': location.address
            }
            
            jQuery.post('/position_success', save_results, function(data, success) {
                jQuery.jGrowl('Your position has been saved.', {'header': 'jMaps Mapping Demo', 'life': 5000});
                jQuery('#map-sidebar').find('#address-find-container').fadeOut('slow', function(){
                    jQuery(this).remove();
                    var thisMap = Mapifies.MapObjects.Get(jQuery('#map').get(0));
                    thisMap.clearOverlays()
                    outputLastTenLocations();
                });
            }, 'json');
        });
    }
        
    });
}

function positionSuccess(position) {
    var sizeControl = new GSmallMapControl(); var typeControl = new GMapTypeControl();
    var overviewControl = new GOverviewMapControl(); var scaleControl = new GScaleControl();
        jQuery('#map').jmap('init', {
            'mapCenter': [position.latitude, position.longitude],
            'mapControl': 'none'
        }, function(map, element,options){
            
            getLocationAddress(position);
            
            jQuery('#change-map-type').change(function(){
                var mapType = jQuery('option:selected', this).val();
                jQuery(element).jmap('SetMapType', mapType);
            });        
            jQuery('#map-control-type').change(function(){
                map.removeControl(sizeControl);
                var control = jQuery('option:selected', this).val();
                if (control !== 'null') {
                    sizeControl = new window[control]();
                    map.addControl(sizeControl);
                }
            });
            //This is just for the first run, as we need to pass it to control it
            map.addControl(sizeControl);
            jQuery('#map-type-toggle').change(function(){
                var control = jQuery(this).is(':checked');
                if (control) {
                    map.addControl(typeControl);
                } else {
                    map.removeControl(typeControl);
                }
            });
            jQuery('#map-overview-toggle').change(function(){
                var control = jQuery(this).is(':checked');
                if (control) {
                    map.addControl(overviewControl);
                } else {
                    map.removeControl(overviewControl);
                }
            });
            jQuery('#map-scale-toggle').change(function(){
                var control = jQuery(this).is(':checked');
                if (control) {
                    map.addControl(scaleControl);
                } else {
                    map.removeControl(scaleControl);
                }
            });
            jQuery('#map-dragging-toggle').change(function(){
                var control = jQuery(this).is(':checked');
                if (control) {
                    map.enableDragging();
                } else {
                    map.disableDragging();
                }
            });
            jQuery('#map-search-toggle').change(function(){
                var control = jQuery(this).is(':checked');
                if (control) {
                    map.enableGoogleBar();
                } else {
                    map.disableGoogleBar();
                }
            });
            jQuery('.get-directions').click(function(){
                var from = jQuery('#from-location').val();
                var to= jQuery('#to-location').val();
            
                jQuery('#map').jmap('SearchDirections', {
                    'query': 'from: ' +  from + ' to: ' + to,
                    'panel':'#directions'
                }); 
            });
        });
    };

    function positionError(error) {
        var errorReturn = 'Geocoder: Unknown Error. Falling back to IP-based location.';
        switch (error.code) {
            case error.UNKNOWN_ERROR:
                errorReturn = 'Geocoder: Unknown Error. Falling back to IP-based location.';
            break;
            case error.PERMISSION_DENIED:
                errorReturn = 'Geocoder: Permission Denied. Falling back to IP-based location.';
            break;
            case error.POSITION_UNAVAILABLE:
                errorReturn = 'Geocoder: Position Unavailable. Falling back to IP-based location.';
            break;
            case error.TIMEOUT:
                errorReturn = 'Geocoder: Timeout. Falling back to IP-based location.';
            break;
            }
     jQuery.jGrowl(errorReturn , {'header': 'jMaps Mapping Demo', 'life': 5000});
     getIpBasedLocation();
    };


/* appjet:css */

body {
    font: 98% Arial, sans-serif;   
}

#map-container {
    float:left;
}

#map-sidebar {
    float:left;
    width: 300px;
}

#map {
    width: 400px;
    height: 400px;
}

#directions {
    width: 400px;
    height:400px;
    overflow-x:none;   
    overflow-y:scroll;
}

#control-panel {
    float:left;   
}

#message {
    width: 100%;
    height: 100px;
    display: none;
}

div.jGrowl {
    padding: 10px;
    z-index: 9999;
}

/** Special IE6 Style Positioning **/
div.ie6 {
    position: absolute;
}

div.ie6.top-right {
    right: auto;
    bottom: auto;
    left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
    top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}

div.ie6.top-left {
    left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
    top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}

div.ie6.bottom-right {
    left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
    top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}

div.ie6.bottom-left {
    left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
    top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
}

div.ie6.center {
    left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
    top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' );
    width: 100%;
}

/** Normal Style Positions **/
body > div.jGrowl {
    position: fixed;
}

body > div.jGrowl.top-left {
    left: 0px;
    top: 0px;
}

body > div.jGrowl.top-right {
    right: 0px;
    top: 0px;
}

body > div.jGrowl.bottom-left {
    left: 0px;
    bottom: 0px;
}

body > div.jGrowl.bottom-right {
    right: 0px;
    bottom: 0px;
}

body > div.jGrowl.center {
    top: 0px;
    width: 50%;
    left: 25%;
}

/** Cross Browser Styling **/
div.center div.jGrowl-notification, div.center div.jGrowl-closer {
    margin-left: auto;
    margin-right: auto;
}

div.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer {
    background-color: #000;
    color: #fff;
    opacity: .85;
    filter: alpha(opacity = 85);
    zoom: 1;
    width: 235px;
    padding: 10px;
    margin-top: 5px;
    margin-bottom: 5px;
    font-family: Tahoma, Arial, Helvetica, sans-serif;
    font-size: 12px;
    text-align: left;
    display: none;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
}

div.jGrowl div.jGrowl-notification {
    min-height: 40px;
}

div.jGrowl div.jGrowl-notification div.header {
    font-weight: bold;
    font-size: 10px;
}

div.jGrowl div.jGrowl-notification div.close {
    float: right;
    font-weight: bold;
    font-size: 12px;
    cursor: pointer;
}

div.jGrowl div.jGrowl-closer {
    height: 15px;
    padding-top: 4px;
    padding-bottom: 4px;
    cursor: pointer;
    font-size: 11px;
    font-weight: bold;
    text-align: center;
}